package org.tri.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.*;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.Formula;

/**
 * La clase {@code AbstractVenta} representa una venta realizada por
 * un establecimiento. Esta clase sirve de base para mantener registro
 * de ventas consideradas actulaes y ventas consideradas históricas.
 * @author kiira
 * @version 1.0, Nov 23, 2011
 */
@MappedSuperclass
public abstract class AbstractVenta implements Serializable, Transaccion {

    /** Identificador único del objeto. */
    private int idVenta;
    /** Número de DTA asignado a la venta. */
    private long nroDta;
    /** Nombre del establecimiento destinatario de la venta. */
    private String destinatario;
    /** Renspa del establecimiento destinatario de la venta. */
    private long renspaDestinatario;
    /** Categoría de los animales vendidos. */
    private Categoria categoria;
    /** Establecimiento al que le corresponde esta venta. */
    private Establecimiento establecimiento;
    /** Fecha de la venta. */
    private Date fecha;
    /**Da la cantidad de animales asociados a la venta*/
    private int cantidadAnimales;

    /**
     * Nos permite obtener el identificador utilizado por Hibernate para identificar una venta
     * @return int identificador de venta
     */
    @Id
    @GeneratedValue ( strategy = GenerationType.IDENTITY )
    @Column ( name = "id_venta", nullable = false )
    public int getIdVenta() {
        return idVenta;

    }//end método getIdVenta

    /**
     * Nos permite modificar el identificador de una venta utilizado por Hibernate. Este método es de uso exclusivo de Hibernate
     * @param id int identificador de venta
     */
    protected void setIdVenta( int id ) {
        idVenta = id;

    }//end método setIdVenta

    /**
     * Nos permite obtener el número de DTA que identifica a una venta
     * @return 
     */
    @Column ( name = "nro_dta", unique = true )
    public long getNroDta() {
        return nroDta;

    }//end método getNroDta

    /**
     * Nos permite modificar el número de DTA de una venta
     * @param dta long número de DTA
     */
    public void setNroDta( long dta ) {
        nroDta = dta;

    }//end método setNroDta

    /**
     * Nos permite obtener el nombre del destinataria de una venta
     * @return String nombre del destinatario
     */
    @Column ( name = "destino_nombre", nullable = false )
    public String getDestinatario() {
        return destinatario;

    }//end método getDestinatario

    /**
     * Nos permite modificar el nombre del destinatario de una venta
     * @param destinatario String nombre del destinatario
     */
    public void setDestinatario( String destinatario ) {
        this.destinatario = destinatario;

    }//end método setDestinatario

    /**
     * Nos permite obtener el número de renspa del destinatario de una venta
     * @return long renspa del destinatario
     */
    @Column ( name = "destino_renspa", nullable = false )
    public long getRenspaDestinatario() {
        return renspaDestinatario;

    }//end método getrenspaDestinatario

    /**
     * Nos permite modificar el número de renspa del destinatario de una venta
     * @param renspa long renspa del destinatario
     */
    public void setRenspaDestinatario( long renspa ) {
        renspaDestinatario = renspa;

    }//end método setRenspaDestinatario

    /**
     * Nos permite obtener la categoria a la cual corresponden los animales asociados a la venta
     * @return Categoria categoria de los animaless
     */
    @ManyToOne ( optional = false )
    @JoinColumn ( name = "categoria" )
    public Categoria getCategoria() {
        return categoria;

    }//end método getCategoria

    /**
     * Nos permite modificar la categoria a la cual pertenecen los animales asociados a una venta
     * @param categoria Categoria categoria de los animales
     */
    public void setCategoria( Categoria categoria ) {
        this.categoria = categoria;

    }//end método setCategoria

    /**
     * Nos permite obtener los datos del establecimiento que vende los animales
     * @return Establecimiento objeto establecimiento
     */
    @ManyToOne ( cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH } )
    @JoinColumn ( name = "establecimiento" )
    @Cascade ( org.hibernate.annotations.CascadeType.SAVE_UPDATE )
    public Establecimiento getEstablecimiento() {
        return establecimiento;

    }//end método getEstablecimiento

    /**
     * Nos permite modificar el establecimiento del cual se venden los animales
     * @param establecimiento Estableciemiento objeto establecimiento
     */
    public void setEstablecimiento( Establecimiento establecimiento ) {
        this.establecimiento = establecimiento;

    }//end método setEstablecimiento

    /**
     * Nos permite obtener la fecha en la cual se realiza la fecha
     * @return Date fecha de la venta
     */
    @Temporal ( TemporalType.DATE )
    @Column ( name = "fecha", nullable = false )
    public Date getFecha() {
        return fecha;

    }//end método getFecha

    /**
     * Nos permite modificar la fecha en la cual se realiza la fecha
     * @param fecha Date decha de la venta
     */
    public void setFecha( Date fecha ) {
        this.fecha = fecha;

    }//end método setFecha
    
    /**
     * Devuelva la cantidad de animales asociados a la venta.
     * @return cantidad de animales asociados a la venta.
     */
    @Basic ( fetch = FetchType.LAZY )
    @Formula ( "(SELECT COUNT(a.id_animal) "
            + "FROM animal a "
            + "WHERE a.venta = id_venta) + "
            + "(SELECT COUNT(ah.id_animal) "
            + "FROM animal_hist ah "
            + "WHERE ah.venta = id_venta )" )
    public int getCantidadAnimales() {
        return this.cantidadAnimales;

    }//end método getCantidadAnimales

    /**
     * Método utilizado por Hibernate para asignar la cantidad de animales.
     * @param cantidad cantidad de animales de la venta.
     */
    protected void setCantidadAnimales( int cantidad ) {
        this.cantidadAnimales = cantidad;

    }//end método setCantidadAnimales

    /**
     * Indica si esta venta es igual a otro objeto pasado por parámetros.
     * Si el otro objeto se trata de un {@code AbstractVenta} como este,
     * se los considera iguales cuando sus propiedades son iguales.
     * @param obj objeto con el cual comparar.
     * @return <li>true si los objetos son equivalentes. 
     *         <li>flase si los objetos no son equivalentes.
     */
    @Override
    public boolean equals( Object obj ) {
        if ( obj == null )
            return false;
        if ( getClass() != obj.getClass() )
            return false;
        final AbstractVenta other = (AbstractVenta)obj;
        if ( this.nroDta != other.nroDta )
            return false;
        if ( this.renspaDestinatario != other.renspaDestinatario )
            return false;
        if ( this.establecimiento != other.establecimiento && ( this.establecimiento == null || !this.establecimiento.equals( other.establecimiento ) ) )
            return false;
        if ( this.fecha != other.fecha && ( this.fecha == null || !this.fecha.equals( other.fecha ) ) )
            return false;
        return true;

    }//end método equals

    /**
     * Devuelve la computación de un número a partir de las propiedades de la 
     * venta, para que el mismo pueda ser insertado en un {@code Set} sin 
     * peligro de que se produzcan inconsistencia en los datos.
     * @return código hash del objeto.
     */
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 59 * hash + (int)( this.nroDta ^ ( this.nroDta >>> 32 ) );
        hash = 59 * hash + (int)( this.renspaDestinatario ^ ( this.renspaDestinatario >>> 32 ) );
        hash = 59 * hash + ( this.establecimiento != null ? this.establecimiento.hashCode() : 0 );
        hash = 59 * hash + ( this.fecha != null ? this.fecha.hashCode() : 0 );
        return hash;

    }//end método hashCode
    
    /**
     * Método abstracto que asocia animales a una venta
     * @param caravana número de caravana
     */
    public abstract void agregarAnimal(Animal animal);
    
    /**
     * Método abstracto que asocia un listado de animales a una venta
     * @param List<Animal> listado de caravanas
     */
    public abstract void agregarAnimales(List<Animal> animales);
    
    /**
     * Método abstracto que permite desligar un animal de una venta
     * @param caravana número de caravana
     */
    public abstract void eliminarAnimal(Animal animal);
    
    /**
     * Método abstracto que permite desligar una lista de animal de una venta.
     * @param List<Animal> listado de caravanas
     */
    public abstract void eliminarAnimales(List<Animal> animales);
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Date obtenerFecha() {
        return getFecha();
        
    }//end método obtenerFecha
    
    /**
     * {@inheritDoc}
     */
    @Override
    public String obtenerTipoMovimiento() {
        return "Venta";
        
    }//end método obtenerTipoMovimiento
    
    /**
     * {@inheritDoc}
     */
    @Override
    public long obtenerNroComprobante() {
        return getNroDta();
        
    }//end método obtenerNroComprobante
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Establecimiento obtenerEstablecimiento() {
        return getEstablecimiento();
        
    }//end método obtenerEstablecimiento
    
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean esEntrada() {
        return false;
        
    }//end método esEntrada
    
    /**
     * {@inheritDoc}
     */
    @Override
    public int obtenerCantidadAnimales(){
        return getCantidadAnimales();
    }
    
}//end clase AbstractVenta

